﻿
// GraphToolXDlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "GraphToolX.h"
#include "GraphToolXDlg.h"
#include "afxdialogex.h"
#include <string>
#include <stdio.h>
#include <direct.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

using namespace std;
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CGraphToolXDlg 对话框



CGraphToolXDlg::CGraphToolXDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_DRAWGRAPH_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	srand(time(NULL)); //置随机数种子
}

void CGraphToolXDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CGraphToolXDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_LOAD, &CGraphToolXDlg::OnBnClickedLoad)
	ON_BN_CLICKED(IDC_DRAW, &CGraphToolXDlg::OnBnClickedDraw)
	ON_BN_CLICKED(IDC_RESET, &CGraphToolXDlg::OnBnClickedReset)
	ON_BN_CLICKED(IDC_DOT, &CGraphToolXDlg::OnBnClickedDot)
	ON_BN_CLICKED(IDC_CalDegree, &CGraphToolXDlg::OnBnClickedCaldegree)
	ON_BN_CLICKED(IDC_CHECK4, &CGraphToolXDlg::OnBnClickedCheck4)
	ON_BN_CLICKED(IDC_BUTTON_outOfRange, &CGraphToolXDlg::OnBnClickedButtonoutofrange)
	ON_BN_CLICKED(IDC_outDeg_output, &CGraphToolXDlg::OnBnClickedoutdegoutput)
	ON_BN_CLICKED(IDC_inDeg_output, &CGraphToolXDlg::OnBnClickedindegoutput)
	ON_BN_CLICKED(IDC_degree_out, &CGraphToolXDlg::OnBnClickeddegreeout)
	ON_BN_CLICKED(IDC_index_check, &CGraphToolXDlg::OnBnClickedindexcheck)
	ON_BN_CLICKED(IDC_index_order0, &CGraphToolXDlg::OnBnClickedindexorder0)
	ON_BN_CLICKED(IDC_index_order1, &CGraphToolXDlg::OnBnClickedindexorder1)
	ON_BN_CLICKED(IDC_generate_p, &CGraphToolXDlg::OnBnClickedgeneratep)
END_MESSAGE_MAP()


// CGraphToolXDlg 消息处理程序

BOOL CGraphToolXDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时，框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	return TRUE;  // 除非将焦点设置到控件，否则返回 TRUE
}

void CGraphToolXDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void CGraphToolXDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CGraphToolXDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

//下面开始是功能的实现
void CGraphToolXDlg::OnBnClickedLoad()
{ //加载图文件
	n = m = 0;
	string filename; //要打开的图文件
	CString str_temp;
	GetDlgItem(IDC_MFCEDITBROWSE1)->GetWindowTextW(str_temp);
	if (str_temp == L"") {
		MessageBox(_T("请选择文件！"), 0, MB_ICONWARNING);
		return;
	}
	filename = CT2A(str_temp.GetString());
	FILE* fp = fopen(filename.c_str(), "r");
	if (fp == NULL) {
		MessageBox(_T("打开文件失败！"), 0, MB_ICONSTOP);
		return;
	}
	int flag = ((CButton*)GetDlgItem(IDC_CHECK1))->GetCheck(); //文件中是否有点边数
	if (flag == 1) { //图文件首行没有点边数
		GetDlgItem(IDC_EDIT_n)->GetWindowTextW(str_temp); //获取输入的点数
		if (str_temp == L"") {
			MessageBox(_T("请输入点数！"), 0, MB_ICONWARNING);
			return;
		}
		string tmp = CT2A(str_temp.GetString());
		n = strtoul(tmp.c_str(), NULL, 10); //记录点数
		GetDlgItem(IDC_EDIT_m)->GetWindowTextW(str_temp); //获取输入的边数
		if (str_temp == L"") {
			MessageBox(_T("请输入边数！"), 0, MB_ICONWARNING);
			return;
		}
		tmp = CT2A(str_temp.GetString());
		m = strtoul(tmp.c_str(), NULL, 10); //记录边数
	}
	else { //图文件中有点边数
		fscanf(fp, "%u%u", &n, &m);
		GetDlgItem(IDC_EDIT_n)->SetWindowTextW(CA2T((to_string(n).c_str()))); //显示点数
		GetDlgItem(IDC_EDIT_m)->SetWindowTextW(CA2T((to_string(m).c_str()))); //显示边数
	}
	if (((CButton*)GetDlgItem(IDC_CHECK2))->GetCheck() == 1) //是否无向图
		isDirect = false; //无向
	else
		isDirect = true; //有向
	//将图文本文件写到内存
	unsigned int _a, _b; double p;
	if (((CButton*)GetDlgItem(IDC_CHECK4))->GetCheck() == 1) { //有重边的，需要去重
		unsigned int _m = 0; //去重后真正的边数
		adjList = vector<vector<unsigned int>>(n);//邻接表
		if (isDirect) { //有向图
			if (((CButton*)GetDlgItem(IDC_CHECK3))->GetCheck() == 1) { //有概率的
				while (fscanf(fp, "%u%u%lf", &_a, &_b, &p) != EOF) { //遍历每一条边
					bool duplicate = false;
					for (unsigned int node : adjList[_a]) { //看看_a->_b是否存在
						if (node == _b) {
							duplicate = true;
							break;
						}
					}
					if (duplicate) //如果有重复边，则此边不保存
						continue;
					adjList[_a].push_back(_b); //保存边
					_m++;
				}
			}
			else { //无概率的
				while (fscanf(fp, "%u%u", &_a, &_b) != EOF) { //遍历每一条边
					bool duplicate = false;
					for (unsigned int node : adjList[_a]) { //看看_a->_b是否存在
						if (node == _b) {
							duplicate = true;
							break;
						}
					}
					if (duplicate) //如果有重复边，则此边不保存
						continue;
					adjList[_a].push_back(_b); //保存边
					_m++;
				}
			}
		}
		else { //无向图
			if (((CButton*)GetDlgItem(IDC_CHECK3))->GetCheck() == 1) { //有概率的
				while (fscanf(fp, "%u%u%lf", &_a, &_b, &p) != EOF) { //遍历每一条边
					bool duplicate = false;
					for (unsigned int node : adjList[_a]) { //看看_a->_b是否存在
						if (node == _b) {
							duplicate = true;
							break;
						}
					}
					if (duplicate) //如果有重复边，则此边不保存
						continue;
					for (unsigned int node : adjList[_b]) { //看看_b->_a是否存在
						if (node == _a) {
							duplicate = true;
							break;
						}
					}
					if (duplicate) //如果有重复边，则此边不保存
						continue;
					adjList[_a].push_back(_b); //保存边
					_m++;
				}
			}
			else { //无概率的
				while (fscanf(fp, "%u%u", &_a, &_b) != EOF) { //遍历每一条边
					bool duplicate = false;
					for (unsigned int node : adjList[_a]) { //看看_a->_b是否存在
						if (node == _b) {
							duplicate = true;
							break;
						}
					}
					if (duplicate) //如果有重复边，则此边不保存
						continue;
					for (unsigned int node : adjList[_b]) { //看看_b->_a是否存在
						if (node == _a) {
							duplicate = true;
							break;
						}
					}
					if (duplicate) //如果有重复边，则此边不保存
						continue;
					adjList[_a].push_back(_b); //保存边
					_m++;
				}
			}
		}
		//完成去重后再写入a和b
		a.reserve(_m); //预分配空间
		b.reserve(_m);
		for (unsigned int i = 0; i < n; i++) { //遍历每个结点
			for (unsigned int node : adjList[i]) { //每个结点的边
				a.push_back(i);
				b.push_back(node);
			}
		}
		GetDlgItem(IDC_EDIT_m)->SetWindowTextW(CA2T((to_string(_m).c_str()))); //显示新边数
		m = _m;
	}
	else { //没有重复边
		a.reserve(m + 500); //预分配空间
		b.reserve(m + 500);
		if (((CButton*)GetDlgItem(IDC_CHECK3))->GetCheck() == 1) { //有概率的
			for (unsigned int i = 0; i < m; i++) { //遍历每一条边
				fscanf(fp, "%u%u%lf", &_a, &_b, &p);
				a.push_back(_a);
				b.push_back(_b);
			}
		}
		else { //没有概率
			for (unsigned int i = 0; i < m; i++) { //遍历每一条边
				fscanf(fp, "%u%u", &_a, &_b);
				a.push_back(_a);
				b.push_back(_b);
			}
		}
	}
	fclose(fp);
	MessageBox(_T("完成！"), 0, MB_ICONINFORMATION);
	//下面是设置组件禁用
	GetDlgItem(IDC_MFCEDITBROWSE1)->EnableWindow(FALSE);
	GetDlgItem(IDC_EDIT_n)->EnableWindow(FALSE);
	GetDlgItem(IDC_EDIT_m)->EnableWindow(FALSE);
	GetDlgItem(IDC_CHECK1)->EnableWindow(FALSE);
	GetDlgItem(IDC_CHECK2)->EnableWindow(FALSE);
	GetDlgItem(IDC_CHECK3)->EnableWindow(FALSE);
	GetDlgItem(IDC_CHECK4)->EnableWindow(FALSE);
	GetDlgItem(IDC_LOAD)->EnableWindow(FALSE);
}

void CGraphToolXDlg::OnBnClickedReset()
{ //复位按钮
	n = m = 0;
	a.clear(); b.clear();
	vector<unsigned int>().swap(a);//释放内存
	vector<unsigned int>().swap(b);
	for (vector<unsigned int>& i : adjList) {
		i.clear();
		vector<unsigned int>().swap(i);
	}
	adjList.clear();
	vector<vector<unsigned int>>().swap(adjList);
	//组件信息还原
	GetDlgItem(IDC_MFCEDITBROWSE1)->SetWindowTextW(_T(""));
	GetDlgItem(IDC_EDIT_n)->SetWindowTextW(_T(""));
	GetDlgItem(IDC_EDIT_m)->SetWindowTextW(_T(""));
	((CButton*)GetDlgItem(IDC_CHECK1))->SetCheck(FALSE);
	((CButton*)GetDlgItem(IDC_CHECK2))->SetCheck(FALSE);
	((CButton*)GetDlgItem(IDC_CHECK3))->SetCheck(FALSE);
	((CButton*)GetDlgItem(IDC_CHECK4))->SetCheck(FALSE);
	GetDlgItem(IDC_LOAD)->EnableWindow(TRUE);
	//下面是设置组件可用
	GetDlgItem(IDC_MFCEDITBROWSE1)->EnableWindow(TRUE);
	GetDlgItem(IDC_EDIT_n)->EnableWindow(TRUE);
	GetDlgItem(IDC_EDIT_m)->EnableWindow(TRUE);
	GetDlgItem(IDC_CHECK1)->EnableWindow(TRUE);
	GetDlgItem(IDC_CHECK2)->EnableWindow(TRUE);
	GetDlgItem(IDC_CHECK3)->EnableWindow(TRUE);
	GetDlgItem(IDC_CHECK4)->EnableWindow(TRUE);
	GetDlgItem(IDC_LOAD)->EnableWindow(TRUE);
	MessageBox(_T("完成！"), 0, MB_ICONINFORMATION);
}

void CGraphToolXDlg::OnBnClickedDot()
{ //生成DOT文件
	CString str_temp; //保存目录
	GetDlgItem(IDC_MFCEDITBROWSE2)->GetWindowTextW(str_temp);
	if (str_temp == L"") {
		MessageBox(_T("请选择目录！"), 0, MB_ICONWARNING);
		return;
	}
	string resultPath = CT2A(str_temp.GetString());
	for (char c : resultPath) { //检查空格
		if (c == ' ') {
			MessageBox(_T("路径中不能有空格！"), 0, MB_ICONWARNING);
			return;
		}
	}
	if (resultPath[resultPath.size() - 1] != '\\')
		resultPath.push_back('\\'); //如果路径最后没有斜杠，加上斜杠
	resultPath += "output.dot";
	//生成dot文件
	if (a.size() <= 0 || b.size() <= 0) {
		MessageBox(_T("请先加载图文件！"), 0, MB_ICONWARNING);
		return;
	}
	//先判断文件是否已存在，防止意外覆盖
	FILE* fp = fopen(resultPath.c_str(), "r");
	if (fp != NULL) { //文件已存在
		fclose(fp);
		fp = NULL;
		UINT ans = MessageBox(_T("output.dot文件已存在，确定覆盖吗？"), 0, MB_YESNO | MB_ICONQUESTION);
		if (ans == IDNO) {
			MessageBox(_T("操作取消！"), 0, MB_ICONWARNING);
			return;
		}
	}
	fp = fopen(resultPath.c_str(), "w");
	if (isDirect) { //画有向图
		fprintf(fp, "digraph G {\n");
		for (unsigned int i = 0; i < m; i++) //遍历每一条边
			fprintf(fp, "\t%u -> %u;\n", a[i], b[i]);
	}
	else { //画无向图
		fprintf(fp, "graph G {\n");
		for (unsigned int i = 0; i < m; i++) //遍历每一条边
			fprintf(fp, "\t%u -- %u;\n", a[i], b[i]);
	}
	fprintf(fp, "}");
	fclose(fp);
	MessageBox(_T("完成！"), 0, MB_ICONINFORMATION);
}

void CGraphToolXDlg::OnBnClickedDraw()
{ //画图
	CString str_temp; //保存目录
	GetDlgItem(IDC_MFCEDITBROWSE2)->GetWindowTextW(str_temp);
	if (str_temp == L"") {
		MessageBox(_T("请选择目录！"), 0, MB_ICONWARNING);
		return;
	}
	string resultPath = CT2A(str_temp.GetString());
	for (char c : resultPath) { //检查空格
		if (c == ' ') {
			MessageBox(_T("路径中不能有空格！"), 0, MB_ICONWARNING);
			return;
		}
	}
	if (resultPath[resultPath.size() - 1] != '\\')
		resultPath.push_back('\\'); //如果路径最后没有斜杠，加上斜杠
	//判断DOT文件是否存在
	FILE* fp = fopen((resultPath + "output.dot").c_str(), "r");
	if (fp == NULL) {
		MessageBox(_T("output.dot不存在！"), 0, MB_ICONSTOP);
		return;
	}
	fclose(fp);
	//判断文件是否会发生覆盖
	fp = fopen((resultPath + "output.png").c_str(), "r");
	if (fp != NULL) { //如果文件已存在
		fclose(fp);
		fp = NULL;
		UINT ans = MessageBox(_T("output.png文件已存在，确定覆盖吗？"), 0, MB_YESNO | MB_ICONQUESTION);
		if (ans == IDNO) {
			MessageBox(_T("操作取消！"), 0, MB_ICONWARNING);
			return;
		}
	}
	//下面开始调用Graphviz生成PNG
	char pwd[1024];
	_getcwd(pwd, 1024); //获取当前主程序exe工作路径
	string _cmd = pwd;
	if (_cmd[_cmd.size() - 1] != '\\')
		_cmd.push_back('\\'); //如果路径最后没有斜杠，加上斜杠
	_cmd = "\"" + _cmd + "Graphviz\\dot.exe\" -Tpng " + resultPath + "output.dot -o " + resultPath + "output.png";
	//_cmd = "\"D:\\project\\C\\DrawGraph\\x64\\Debug\\Graphviz\\dot.exe\" -Tpng " + resultPath + "output.dot -o " + resultPath + "output.png";
	int code = system(_cmd.c_str());
	if (code == 0)
		MessageBox(_T("完成！"), 0, MB_ICONINFORMATION);
	else
		MessageBox(_T("出错！"), 0, MB_ICONSTOP);
}


void CGraphToolXDlg::OnBnClickedCaldegree()
{ //计算度（保证结点编号从0开始且连续）
	if (n == 0 || m == 0) {
		MessageBox(_T("请先加载图文件！"), 0, MB_ICONWARNING);
		return;
	}
	vector<unsigned int> degIn(n, 0), degOut(n, 0); //统计每个结点的入度和出度
	for (unsigned int i = 0; i < m; i++) { //一条条边遍历，a[i]->b[i]
		degOut[a[i]]++; //出度
		degIn[b[i]]++; //入度
	}
	maxOutDeg = 0; maxInDeg = 0;
	double avgOutDeg = 0.0, avgInDeg = 0.0, avg = 0.0; //平均值
	for (unsigned int i = 0; i < n; i++) { //遍历每个结点，统计最大出度入度
		maxOutDeg = max(maxOutDeg, degOut[i]); //出度
		avgOutDeg += degOut[i];
		maxInDeg = max(maxInDeg, degIn[i]); //入度
		avgInDeg += degIn[i];
		avg += (double)degOut[i] + degIn[i];
	}
	GetDlgItem(IDC_EDIT_max_outDegree)->SetWindowTextW(CA2T(to_string(maxOutDeg).c_str())); //显示最大出度
	GetDlgItem(IDC_EDIT_max_inDegree)->SetWindowTextW(CA2T(to_string(maxInDeg).c_str())); //显示最大入度
	unsigned int countMaxOut = 0, countMaxIn = 0; //个数
	for (unsigned int i = 0; i < n; i++) { //遍历每个结点，统计最大度的结点出现的次数
		if (degOut[i] == maxOutDeg)
			countMaxOut++;
		if (degIn[i] == maxInDeg)
			countMaxIn++;
	}
	GetDlgItem(IDC_EDIT_max_outDegree2)->SetWindowTextW(CA2T(to_string(countMaxOut).c_str())); //显示个数
	GetDlgItem(IDC_EDIT_max_inDegree2)->SetWindowTextW(CA2T(to_string(countMaxIn).c_str()));
	avgOutDeg /= n; //计算平均值
	avgInDeg /= n;
	avg /= n;
	GetDlgItem(IDC_EDIT_avg_outDegree)->SetWindowTextW(CA2T(to_string(avgOutDeg).c_str())); //显示平均值
	GetDlgItem(IDC_EDIT_avg_inDegree)->SetWindowTextW(CA2T(to_string(avgInDeg).c_str()));
	GetDlgItem(IDC_EDIT_avg_degree)->SetWindowTextW(CA2T(to_string(avg).c_str()));
}


void CGraphToolXDlg::OnBnClickedCheck4()
{ //含重复边候选框点击事件
	if (((CButton*)GetDlgItem(IDC_CHECK4))->GetCheck() == 1) //选中时才弹出提示
		MessageBox(_T("图文件中的结点必须从0开始连续编号！"), 0, MB_ICONWARNING);
}

void CGraphToolXDlg::reOrder(int beginNum) { //重新编号
	if (n == 0 || m == 0) {
		MessageBox(_T("请先加载图文件！"), 0, MB_ICONWARNING);
		return;
	}
	CString str_temp; //保存目录
	GetDlgItem(IDC_MFCEDITBROWSE2)->GetWindowTextW(str_temp);
	if (str_temp == L"") {
		MessageBox(_T("请选择目录！"), 0, MB_ICONWARNING);
		return;
	}
	string resultPath = CT2A(str_temp.GetString());
	if (resultPath[resultPath.size() - 1] != '\\')
		resultPath.push_back('\\'); //如果路径最后没有斜杠，加上斜杠
	if (beginNum == 0)
		resultPath += "0.graph.txt";
	else //从1开始编号
		resultPath += "1.graph.txt";
	FILE* fp = fopen(resultPath.c_str(), "r");
	if (fp != NULL) { //文件已存在
		fclose(fp);
		fp = NULL;
		UINT ans;
		if (beginNum == 0)
			ans = MessageBox(_T("0.graph.txt文件已存在，确定覆盖吗？"), 0, MB_YESNO | MB_ICONQUESTION);
		else
			ans = MessageBox(_T("1.graph.txt文件已存在，确定覆盖吗？"), 0, MB_YESNO | MB_ICONQUESTION);
		if (ans == IDNO) {
			MessageBox(_T("操作取消！"), 0, MB_ICONWARNING);
			return;
		}
	}
	unsigned int maxId = 0; //最大的结点ID
	for (unsigned int node : a) //寻找最大值
		maxId = max(maxId, node);
	for (unsigned int node : b)
		maxId = max(maxId, node);
	vector<bool> flag(maxId + 1, false); //结点是否存在
	vector<unsigned int> data(maxId + 1, 0); //新编号
	for (unsigned int node : a)
		flag[node] = true; //标记存在的结点
	for (unsigned int node : b)
		flag[node] = true;
	unsigned int count = beginNum; //【从0开始的新编号】
	for (unsigned int i = 0; i <= maxId; i++) { //开始重新编号
		if (flag[i]) //如果结点存在
			data[i] = count++; //给新编号
	}//编号重编完毕，下面开始输出文件
	fp = fopen(resultPath.c_str(), "w");
	if (((CButton*)GetDlgItem(IDC_CHECK1))->GetCheck() == 0) //文件中含点边数
		fprintf(fp, "%u\t%u\n", n, m); //输出点数边数
	for (unsigned int i = 0; i < m; i++) //输出新的编号
		fprintf(fp, "%u\t%u\n", data[a[i]], data[b[i]]);
	fclose(fp);
	if (beginNum == 0)
		MessageBox(_T("完成！0.graph.txt"), 0, MB_ICONINFORMATION);
	else
		MessageBox(_T("完成！1.graph.txt"), 0, MB_ICONINFORMATION);
}

void CGraphToolXDlg::OnBnClickedindexorder0()
{ //使结点从0开始编号
	reOrder(0);
}

void CGraphToolXDlg::OnBnClickedindexorder1()
{ //使结点从1开始编号
	reOrder(1);
}

void CGraphToolXDlg::OnBnClickedindexcheck()
{ //点编号连续性判断
	if (n == 0 || m == 0) {
		MessageBox(_T("请先加载图文件！"), 0, MB_ICONWARNING);
		return;
	}
	unsigned int maxId = 0;
	for (unsigned int node : a)
		maxId = max(maxId, node);
	for (unsigned int node : b)
		maxId = max(maxId, node);
	//最大值获取完毕，下面开始统计
	vector<bool> _flag(maxId + 1, false); //标记每个点是否出现过
	unsigned int count = 0; //真正的结点数
	for (unsigned int node : a) {
		if (!_flag[node])
			count++;
		_flag[node] = true;
	}
	for (unsigned int node : b) {
		if (!_flag[node])
			count++;
		_flag[node] = true;
	}
	//得出结论（从maxId开始向前遍历count个_flag数组成员，如果遇到false说明不连续）
	unsigned int i = maxId;
	while (count--) {
		if (!_flag[i--]) {
			MessageBox(_T("结点编号不连续！"), 0, MB_ICONSTOP);
			return;
		}
	}
	string s = "结点编号连续！范围：[" + to_string(i + 1) + "," + to_string(maxId) + "]";
	MessageBox(CA2T(s.c_str()), 0, MB_ICONINFORMATION);
}

void CGraphToolXDlg::OnBnClickedgeneratep()
{  //生成边上的权重
	if (n == 0 || m == 0) {
		MessageBox(_T("请先加载图文件！"), 0, MB_ICONWARNING);
		return;
	}
	CString str_temp; //保存目录
	GetDlgItem(IDC_MFCEDITBROWSE2)->GetWindowTextW(str_temp);
	if (str_temp == L"") {
		MessageBox(_T("请选择目录！"), 0, MB_ICONWARNING);
		return;
	}
	string resultPath = CT2A(str_temp.GetString());
	if (resultPath[resultPath.size() - 1] != '\\')
		resultPath.push_back('\\'); //如果路径最后没有斜杠，加上斜杠
	resultPath += "graph.weighted.txt";
	char type = 0;
	if (((CButton*)GetDlgItem(IDC_RADIO1))->GetCheck() == 1) { //固定值
		GetDlgItem(IDC_fixP)->GetWindowTextW(str_temp);
		if (str_temp == L"") {
			MessageBox(_T("请输入固定值！"), 0, MB_ICONWARNING);
			return;
		}
		type = 1;
	}
	else if (((CButton*)GetDlgItem(IDC_RADIO2))->GetCheck() == 1) //随机值
		type = 2;
	else if (((CButton*)GetDlgItem(IDC_RADIO3))->GetCheck() == 1) // 1/deg_in
		type = 3;
	else if (((CButton*)GetDlgItem(IDC_RADIO4))->GetCheck() == 1) // 1/deg_out
		type = 4;
	else if (((CButton*)GetDlgItem(IDC_RADIO5))->GetCheck() == 1) // 1/n
		type = 5;
	else {
		MessageBox(_T("请选择一种生成权重的方式！"), 0, MB_ICONWARNING);
		return;
	}
	FILE* fp = fopen(resultPath.c_str(), "r");
	if (fp != NULL) { //如果文件已存在
		fclose(fp);
		fp = NULL;
		UINT ans = MessageBox(_T("graph.weighted.txt文件已存在，确定覆盖吗？"), 0, MB_YESNO | MB_ICONQUESTION);
		if (ans == IDNO) {
			MessageBox(_T("操作取消！"), 0, MB_ICONWARNING);
			return;
		}
	}
	fp = fopen(resultPath.c_str(), "w");
	if (((CButton*)GetDlgItem(IDC_CHECK1))->GetCheck() == 0) //文件中含点边数
		fprintf(fp, "%u\t%u\n", n, m); //输出点数边数
	double p;
	vector<unsigned int> degree; //每个结点的度
	switch (type)
	{
	case 1: //固定值
		p = atof(CT2A(str_temp.GetString()));
		for (unsigned int i = 0; i < m; i++)
			fprintf(fp, "%u\t%u\t%lf\n", a[i], b[i], p);
		break;
	case 2: //随机值
		for (unsigned int i = 0; i < m; i++) {
			while ((p = rand() % 1000000 / (double)1e6) == 0.0)
				p = rand() % 1000000 / (double)1e6; //产生(0,1)之间的随机数
			fprintf(fp, "%u\t%u\t%lf\n", a[i], b[i], p);
		}
		break;
	case 3: // 1/deg_in入度
		degree = vector<unsigned int>(n, 0);
		if (isDirect) { //有向图
			for (unsigned int node : b)
				degree[node]++; //统计入度
		}
		else { //无向图
			for (unsigned int node : a)
				degree[node]++;
			for (unsigned int node : b)
				degree[node]++;
		}
		for (unsigned int i = 0; i < m; i++) {
			if (degree[b[i]] == 0)
				p = 1.0; //如果入度为0，权重直接为1
			else
				p = 1.0 / degree[b[i]];
			fprintf(fp, "%u\t%u\t%lf\n", a[i], b[i], p);
		}
		break;
	case 4: // 1/deg_out出度
		degree = vector<unsigned int>(n, 0);
		if (isDirect) { //有向图
			for (unsigned int node : a)
				degree[node]++; //统计出度
		}
		else { //无向图
			for (unsigned int node : a)
				degree[node]++;
			for (unsigned int node : b)
				degree[node]++;
		}
		for (unsigned int i = 0; i < m; i++) {
			if (degree[a[i]] == 0)
				p = 1.0; //如果出度为0，权重直接为1
			else
				p = 1.0 / degree[a[i]];
			fprintf(fp, "%u\t%u\t%lf\n", a[i], b[i], p);
		}
		break;
	case 5: // 1/n
		p = 1.0 / n;
		for (unsigned int i = 0; i < m; i++)
			fprintf(fp, "%u\t%u\t%lf\n", a[i], b[i], p);
		break;
	}
	fclose(fp);
	MessageBox(_T("完成！graph.weighted.txt"), 0, MB_ICONINFORMATION);
}

void CGraphToolXDlg::OnBnClickeddegreeout()
{ //输出各结点的总度，无向图通用
	if (n == 0 || m == 0) {
		MessageBox(_T("请先加载图文件！"), 0, MB_ICONWARNING);
		return;
	}
	CString str_temp; //保存目录
	GetDlgItem(IDC_MFCEDITBROWSE2)->GetWindowTextW(str_temp);
	if (str_temp == L"") {
		MessageBox(_T("请选择目录！"), 0, MB_ICONWARNING);
		return;
	}
	string resultPath = CT2A(str_temp.GetString());
	if (resultPath[resultPath.size() - 1] != '\\')
		resultPath.push_back('\\'); //如果路径最后没有斜杠，加上斜杠
	resultPath += "NodeDegree.txt";
	FILE* fp = fopen(resultPath.c_str(), "r");
	if (fp != NULL) { //如果文件已存在
		fclose(fp);
		fp = NULL;
		UINT ans = MessageBox(_T("NodeDegree.txt文件已存在，确定覆盖吗？"), 0, MB_YESNO | MB_ICONQUESTION);
		if (ans == IDNO) {
			MessageBox(_T("操作取消！"), 0, MB_ICONWARNING);
			return;
		}
	}
	vector<unsigned int> degree(n, 0); //统计每个结点的总度，无向图在打开的时候就只保留一个方向了
	for (unsigned int i = 0; i < m; i++) { //一条条边遍历，a[i]->b[i]
		degree[a[i]]++; //出度
		degree[b[i]]++; //入度
	}
	fp = fopen(resultPath.c_str(), "w");
	fprintf(fp, "Id\tDegree\n");
	for (unsigned int i = 0; i < n; i++) //输出各个点的总度
		fprintf(fp, "%u\t%u\n", i, degree[i]);
	fclose(fp);
	MessageBox(_T("完成！NodeDegree.txt"), 0, MB_ICONINFORMATION);
}

void CGraphToolXDlg::OnBnClickedoutdegoutput()
{ //输出各结点出度（保证从0开始并且连续）
	if (n == 0 || m == 0) {
		MessageBox(_T("请先加载图文件！"), 0, MB_ICONWARNING);
		return;
	}
	CString str_temp; //保存目录
	GetDlgItem(IDC_MFCEDITBROWSE2)->GetWindowTextW(str_temp);
	if (str_temp == L"") {
		MessageBox(_T("请选择目录！"), 0, MB_ICONWARNING);
		return;
	}
	string resultPath = CT2A(str_temp.GetString());
	if (resultPath[resultPath.size() - 1] != '\\')
		resultPath.push_back('\\'); //如果路径最后没有斜杠，加上斜杠
	resultPath += "NodeOutDegree.txt";
	FILE* fp = fopen(resultPath.c_str(), "r");
	if (fp != NULL) { //如果文件已存在
		fclose(fp);
		fp = NULL;
		UINT ans = MessageBox(_T("NodeOutDegree.txt文件已存在，确定覆盖吗？"), 0, MB_YESNO | MB_ICONQUESTION);
		if (ans == IDNO) {
			MessageBox(_T("操作取消！"), 0, MB_ICONWARNING);
			return;
		}
	}
	vector<unsigned int> degOut(n, 0); //统计每个结点的出度
	for (unsigned int i = 0; i < m; i++) //一条条边遍历，a[i]->b[i]
		degOut[a[i]]++; //出度
	fp = fopen(resultPath.c_str(), "w");
	fprintf(fp, "Id\toutDegree\n");
	for (unsigned int i = 0; i < n; i++) //输出各个点的出度
		fprintf(fp, "%u\t%u\n", i, degOut[i]);
	fclose(fp);
	MessageBox(_T("完成！NodeOutDegree.txt"), 0, MB_ICONINFORMATION);
}

void CGraphToolXDlg::OnBnClickedindegoutput()
{ //输出各结点入度（保证从0开始并且连续）
	if (n == 0 || m == 0) {
		MessageBox(_T("请先加载图文件！"), 0, MB_ICONWARNING);
		return;
	}
	CString str_temp; //保存目录
	GetDlgItem(IDC_MFCEDITBROWSE2)->GetWindowTextW(str_temp);
	if (str_temp == L"") {
		MessageBox(_T("请选择目录！"), 0, MB_ICONWARNING);
		return;
	}
	string resultPath = CT2A(str_temp.GetString());
	if (resultPath[resultPath.size() - 1] != '\\')
		resultPath.push_back('\\'); //如果路径最后没有斜杠，加上斜杠
	resultPath += "NodeInDegree.txt";
	FILE* fp = fopen(resultPath.c_str(), "r");
	if (fp != NULL) { //如果文件已存在
		fclose(fp);
		fp = NULL;
		UINT ans = MessageBox(_T("NodeInDegree.txt文件已存在，确定覆盖吗？"), 0, MB_YESNO | MB_ICONQUESTION);
		if (ans == IDNO) {
			MessageBox(_T("操作取消！"), 0, MB_ICONWARNING);
			return;
		}
	}
	vector<unsigned int> degIn(n, 0); //统计每个结点的入度
	for (unsigned int i = 0; i < m; i++) //一条条边遍历，a[i]->b[i]
		degIn[b[i]]++; //入度
	fp = fopen(resultPath.c_str(), "w");
	fprintf(fp, "Id\tinDegree\n");
	for (unsigned int i = 0; i < n; i++) //输出各个点的入度
		fprintf(fp, "%u\t%u\n", i, degIn[i]);
	fclose(fp);
	MessageBox(_T("完成！NodeInDegree.txt"), 0, MB_ICONINFORMATION);
}

void CGraphToolXDlg::OnBnClickedButtonoutofrange()
{ //点越界判断（实际的结点个数是否>n）
	if (n == 0 || m == 0) {
		MessageBox(_T("请先加载图文件！"), 0, MB_ICONWARNING);
		return;
	}
	unsigned int maxId = 0; //结点ID的最大值
	for (unsigned int node : a)
		maxId = max(maxId, node);
	for (unsigned int node : b)
		maxId = max(maxId, node);
	//最大值获取完毕，下面开始统计
	vector<bool> _flag(maxId + 1, false); //标记每个点是否出现过
	unsigned int count = 0;
	for (unsigned int node : a) {
		if (!_flag[node])
			count++;
		_flag[node] = true;
	}
	for (unsigned int node : b) {
		if (!_flag[node])
			count++;
		_flag[node] = true;
	}
	//得出结论
	if (count > n)
		MessageBox(_T("存在越界！实际的结点个数 > n"), 0, MB_ICONSTOP);
	else if (count < n)
		MessageBox(_T("存在“实现结点个数 < n”的情况！"), 0, MB_ICONWARNING);
	else
		MessageBox(_T("没发现越界~"), 0, MB_ICONINFORMATION);
}
